package pl.edu.pk.mech.kkbus.service;

import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Query;

import org.apache.commons.codec.digest.DigestUtils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import pl.edu.pk.mech.kkbus.component.ExternalEmailSender;
import pl.edu.pk.mech.kkbus.component.MyEntityManagerFactory;
import pl.edu.pk.mech.kkbus.entities.User;
import pl.edu.pk.mech.kkbus.dto.AuthenticatedUser;
import pl.edu.pk.mech.kkbus.dto.UserWithRole;
import pl.edu.pk.mech.kkbus.dto.NewUser;
import pl.edu.pk.mech.kkbus.dto.ManageUser;

@Service
public class UserService
{   
    
    private static final Logger log = Logger.getLogger(UserService.class.getName());
    
    @Autowired
    ExternalEmailSender emailSender;
    
    EntityManagerFactory emf = MyEntityManagerFactory.get();
    
    public User getUserByEmail(String email) {
        EntityManager em = null;
        
        try {
            em = emf.createEntityManager();
            Query query = em.createQuery("SELECT u FROM User u WHERE u.email = :email");
            query.setParameter("email", email);
            User user = (User) query.getSingleResult();
            
            return user;
         
        } catch(NoResultException e) {
            return null;
        } finally {
            if (em != null)
                em.close();
        }
    }
    
    public AuthenticatedUser getAuthenticatedUser(String email) {
        User user = getUserByEmail(email);
        
        return new AuthenticatedUser(user.getKey().getId(), user.getName(), 
                user.getSurname(), user.getBirthday(), email, user.getPhone(),
                user.getPoints(), user.getRoles());
    }
    
    public List<UserWithRole> getUsersByRole(User.Role role) {
    	List<UserWithRole> result = new LinkedList<UserWithRole>();
        EntityManager em = null;        
        try {
            em = emf.createEntityManager();
            Query query = em.createQuery("SELECT u FROM User u");
            List<User> results = (List<User>) query.getResultList();
            Iterator<User> iterator = results.iterator();
            while (iterator.hasNext()) {                
                User user = iterator.next();
                
                // TODO Filtracja tu bądź w UI
                if (user.getRoles().contains(role)) {
                    result.add(new UserWithRole(user.getKey().getId(), 
                            user.getName(), user.getSurname(), user.getRoles()));
                }
            }
            
            return result;         
        } catch(NoResultException e) {
            return null;
        } finally {
            if (em != null)
                em.close();
        }
    }
    
    public boolean createUser(NewUser newUser) {
        User user = getUserByEmail(newUser.getEmail());
        if(user != null) {
            log.info("User with email " + newUser.getEmail() + " already exists!");
            return false;
        } else {
            user = new User();
        }
        
        EntityManager em = null;        
        try {
            em = emf.createEntityManager();
            
            user.setBirthday(newUser.getBirthday());
            user.setEmail(newUser.getEmail());
            user.setEnabled(false);
            user.setHash(DigestUtils.md5Hex(String.valueOf(new Date()) + "pHe1Ux7kJA")); //salt
            user.setName(newUser.getName());
            user.setPassword(DigestUtils.md5Hex(newUser.getPassword()));
            user.setPhone(newUser.getPhone());
            user.setPoints(0);
            Set<User.Role> roles = new LinkedHashSet<User.Role>();
            roles.add(User.Role.USER);
            user.setRoles(roles);
            user.setSurname(newUser.getSurname());
            
            em.persist(user);
            
            String message = "Link do aktywacji: http://localhost:8080/#user/activate/" + user.getHash();
            emailSender.send(user.getEmail(), "KKBus - Aktywacja Konta", message);
            
            return true;
        } catch(Exception e) {
            return false;
        } finally {
            if (em != null)
                em.close();
        }
    }
    
    public boolean updateUser(long userId, ManageUser manageUser) {
        EntityManager em = null; 
        try {
            em = emf.createEntityManager();
            
            User user = em.find(User.class, userId);
            // TODO Weryfikacja czy dany email istnieje
            user.setEmail(manageUser.getEmail());
            user.setName(manageUser.getName());
            if (manageUser.getPassword() != null && !manageUser.getPassword().equals("")) {
                user.setPassword(DigestUtils.md5Hex(manageUser.getPassword()));
            }
            user.setPhone(manageUser.getPhone());
            user.setSurname(manageUser.getSurname());
            user.setRoles(manageUser.getRoles());
            
            em.persist(user);
            
            return true;
        } catch(Exception e) {
            return false;
        } finally {
            if (em != null)
                em.close();
        }           
    }
     
    public boolean activateUser(String hash) {
        EntityManager em = null;
        
        try {
            em = emf.createEntityManager();
            Query query = em.createQuery("SELECT u FROM User u WHERE u.hash = :hash");
            query.setParameter("hash", hash);
            User user = (User) query.getSingleResult();
            user.setEnabled(true);
            user.setHash("");
            
            em.persist(user);
            
            return true;         
        } catch(NoResultException e) {
            return false;
        } finally {
            if (em != null)
                em.close();
        }
    }
    
    public boolean deleteUser(long userId) {
        // TODO Usunięcie wymian i grafiku pracy
        
        EntityManager em = null;        
        try {
            em = emf.createEntityManager();
            User user = em.find(User.class, new Long(userId));
            if (user == null) return false;
            
            em.remove(user);
            log.info("Deleting user with id " + userId + " success!");
            return true;
        } catch(Exception e) {
            return false;
        } finally {
            if (em != null)
                em.close();
        }
    }
    
    public boolean banOrUnbanUser(long userId, boolean ban) {
        EntityManager em = null;        
        try {
            em = emf.createEntityManager();
            User user = em.find(User.class, new Long(userId));
            if (user == null) {
                return false;
            } else {
                if (ban) {
                    user.setEnabled(false);
                    log.info("Ban user with id " + userId);
                } else {
                    user.setEnabled(true); 
                    log.info("Unban user with id " + userId);
                }
                
                em.persist(user);
            }           
            
            return true;
        } catch(Exception e) {
            return false;
        } finally {
            if (em != null)
                em.close();
        }
    }
}